﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace winform_demo._2_页_界_面跳转
{
    internal class PageManager
    {
        /// <summary>
        /// 页面容器控件
        /// </summary>
        private static ScrollableControl container;
        /// <summary>
        /// 页面实例栈，用于记录跳转历史
        /// </summary>
        private static Stack<IPage> pageHistory;
        /// <summary>
        /// 存储所有页面实例，方便查找
        /// </summary>
        private static List<IPage> pageList;
        /// <summary>
        /// 保存被移出栈的页面实例的栈
        /// </summary>
        private static Stack<IPage> popedPages;
        /// <summary>
        /// 当前程序的使用者角色/身份拥有的权限
        /// </summary>
        public static Authority Role { get; set; }

        static PageManager()
        {
            pageHistory = new Stack<IPage>();
            pageList = new List<IPage>();
            popedPages = new Stack<IPage>();
        }

        /// <summary>
        /// 注册页面类。注册成功后该页面类的实例原则上交由页面管理器管理
        /// </summary>
        /// <typeparam name="T">页面类</typeparam>
        /// <param name="defaultPage">是否为初始页面</param>
        /// <returns>注册成功返回true，否则返回false</returns>
        public static bool RegisterPage<T>(bool defaultPage = false) where T : Control, new()
        {
            //pageType必须既是IPage接口类型又是Control类型，同时必须具有无参构造
            Type pageType = typeof(T);
            var x = pageType.GetInterface("IPage");
            if (x != null)
            {
                var page = new T() as IPage;
                pageList.Add(page);
                if (defaultPage)
                {
                    NavigateTo<T>();
                }
                return true;
            }

            return false;
        }
        /// <summary>
        /// 刷新页面
        /// </summary>
        public static void Flush()
        {
            if (container.Controls.Count > 0)
            {
                if (pageHistory.Count > 0)
                {
                    //判定容器内的页面是否与栈顶一致
                    if (container.Controls[0] != pageHistory.First())
                    {
                        var newPage = pageHistory.First();
                        if (newPage.Cached)
                        {
                            newPage.Restore();
                        }
                        else
                        {
                            newPage.Reset();
                        }
                        container.Controls.Clear();
                        Control pageCtrl = newPage as Control;
                        if (pageCtrl is Form)
                        {
                            Form form = (Form)pageCtrl;
                            form.ControlBox = false;
                            form.FormBorderStyle = FormBorderStyle.None;
                            form.TopLevel = false;
                        }
                        pageCtrl.Dock = DockStyle.Fill;
                        container.Controls.Add(pageCtrl);
                        pageCtrl.Show();
                        container.Update();
                    }
                }
                else
                {
                    container.Controls.Clear();
                    container.Update();
                }
            }
            else
            {
                if (pageHistory.Count > 0)
                {
                    var newPage = pageHistory.First();
                    if (newPage.Cached)
                    {
                        newPage.Restore();
                    }
                    else
                    {
                        newPage.Reset();
                    }
                    Control pageCtrl = newPage as Control;
                    if (pageCtrl is Form)
                    {
                        Form form = (Form)pageCtrl;
                        form.ControlBox = false;
                        form.FormBorderStyle = FormBorderStyle.None;
                        form.TopLevel = false;
                    }
                    pageCtrl.Dock = DockStyle.Fill;
                    container.Controls.Add(pageCtrl);
                    pageCtrl.Show();
                    container.Update();
                }
            }
        }
        /// <summary>
        /// 跳转到指定页面（不带参数）
        /// </summary>
        /// <typeparam name="T">页面类</typeparam>
        public static void NavigateTo<T>() where T : Control, new()
        {
            foreach (var page in pageList)
            {
                if (page is T)
                {
                    //根据权限决定是否压入栈，权限的判定规则：使用者拥有权限必须包含页面访问权限
                    if ((Role & page.Authority) > 0)
                    {
                        //压栈时，如果跳转历史栈中有元素，则找到栈顶元素保留当前页面状态
                        if (pageHistory.Count > 0)
                        {
                            pageHistory.First().Pause();
                        }
                        pageHistory.Push(page);
                        Flush();
                    }
                    else
                    {
                        MessageBox.Show("您没有该页面的访问权限！", "权限");
                    }
                }
            }
        }

        public static void NavigateTo<T>(Dictionary<string,object> paramMap) where T : Control, new()
        {
            foreach (var page in pageList)
            {
                if (page is T)
                {
                    if ((Role & page.Authority) > 0)
                    {
                        if (pageHistory.Count > 0)
                        {
                            pageHistory.First().Pause();
                        }
                        //如果该页面类身上具有与参数字典的key名相同的字段或属性，则将对应的value转换并赋值
                        Type t = typeof(T);
                        foreach (var key in paramMap.Keys)
                        {
                            var fieldInfo1 = t.GetField(key,BindingFlags.NonPublic|BindingFlags.Instance);
                            if (fieldInfo1 != null)
                            {
                                fieldInfo1.SetValue(page, paramMap[key]);
                                continue;
                            }
                            var fieldInfo2 = t.GetField(key);
                            if (fieldInfo2 != null)
                            {
                                fieldInfo2.SetValue(page, paramMap[key]);
                                continue;
                            }
                            var propInfo = t.GetProperty(key, paramMap[key].GetType());
                            if (propInfo != null)
                            {
                                propInfo.SetValue(page, paramMap[key]);
                            }
                        }
                        pageHistory.Push(page);
                        Flush();
                    }
                    else
                    {
                        MessageBox.Show("您没有该页面的访问权限！", "权限");
                    }

                    break;
                }
            }
        }
        /// <summary>
        /// 返回到上一个页面
        /// </summary>
        /// <returns>执行返回操作前的当前页面</returns>
        public static IPage Back()
        {
            if (pageHistory.Count > 1)
            {
                var oldPage = pageHistory.Pop();
                oldPage.Pause();
                popedPages.Push(oldPage);
                Flush();
                return oldPage;
            }
            return null;
        }
        /// <summary>
        /// 撤销返回上一个页面
        /// </summary>
        public static void GoBackBack()
        {
            if (popedPages.Count > 0)
            {
                var page = popedPages.Pop();
                if (pageHistory.Count > 0)
                {
                    pageHistory.First().Pause();
                }

                pageHistory.Push(page);
                Flush();
            }
        }
        /// <summary>
        /// 设置指定页面是否缓存
        /// </summary>
        /// <typeparam name="T">页面类</typeparam>
        /// <param name="cached">缓存标志,true表示缓存页面</param>
        public static void SetCached<T>(bool cached) where T : Control, new()
        {
            foreach (var page in pageList)
            {
                if (page is T)
                {
                    page.Cached = cached;
                }
            }
        }
        /// <summary>
        /// 设置页面访问权限
        /// </summary>
        /// <typeparam name="T">页面类</typeparam>
        /// <param name="authority">访问权限枚举</param>
        public static void SetAccessAuthority<T>(Authority authority) where T : Control, new()
        {
            foreach (var page in pageList)
            {
                if (page is T)
                {
                    page.Authority = authority;
                }
            }
        }
        /// <summary>
        /// 设置容器
        /// </summary>
        /// <param name="container"></param>
        public static void SetContainer(ScrollableControl container)
        {
            PageManager.container = container;
        }
    }
}
